package chances.epg.data.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import chances.epg.commons.log.EpgLogFactory;
import chances.epg.commons.utils.DateUtils;
import chances.epg.data.PageBean;
import chances.epg.entity.content.CategoryItem;
import chances.epg.entity.content.Channel;
import chances.epg.entity.content.ChannelParameter;
import chances.epg.entity.content.Schedule;

@Service
public class ChannelService extends EpgService {
	private static Logger logger = EpgLogFactory.getSystemLogger();
	/**
	 * 用于缓存频道当前节目单
	 */
	private static Map<String, Schedule> nowSchedules = new ConcurrentHashMap<String, Schedule>();
	/**
	 * 用户缓存频道下一条节目单
	 */
	private static Map<String, Schedule> nextSchedules = new ConcurrentHashMap<String, Schedule>();
	
	/**
	 * 用于缓存直播频道
	 */
	private Map<String,Channel> channelMap = new ConcurrentHashMap<String, Channel>();
	private List<Channel> channleList  = new ArrayList<Channel>();
	
	@PostConstruct
	public void init() {
		this.loadChannels();
		this.loadSchedules();
	}
	
	/**
	 * 后台定时读取直播频道当前节目单.
	 */
	@Scheduled(cron="0 */1 * * * ?")
	public void loadSchedules() {
		logger.debug("Loading current schedules...");
		//装载当前的节目单
		this.loadNowSchedules();
		logger.debug("Loading next schedules...");
		//装载下一条节目单
		this.loadNextSchedules();
	}
	
	/**
	 * 后台定时装载直播频道信息.
	 */
	@Scheduled(cron="0 */5 * * * ?")
	public void loadChannels() {
		logger.debug("Loading channels...");
		List<Channel> result = this.getAllChannels();
		Map<String,Channel> channelMap = new ConcurrentHashMap<String, Channel>();
		for (Channel channel : result) {
			channelMap.put(channel.getContentCode(), channel);
		}
		
		//查询频道参数，设置到频道中.
		List<ChannelParameter> params = this.getAllChannelParameters();
		for (ChannelParameter param : params) {
			Channel channel = channelMap.get(param.getChannelCode());
			if(channel != null){
				channel.addParameter(param);
			}
		}
		
		List<Channel> oldList = this.channleList;
		this.channleList = result;
		oldList.clear();
		oldList = null;
		
		Map<String,Channel> old = this.channelMap;
		this.channelMap = channelMap;
		old.clear();
		old = null;
	}
	
	/**
	 * 获取所有的直播频道信息.
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<Channel> getAllChannels() {
		return (List<Channel>)this.queryForList("getAllChannles");
	}
	
	/**
	 * 获取所有直播频道的参数.
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private List<ChannelParameter> getAllChannelParameters() {
		return (List<ChannelParameter>)this.queryForList("getAllChannleParameters");
	}

	/**
	 * 
	 * @param channelCode
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Channel getChannelByCode(String channelCode) {
		Channel cacheChannel = this.channelMap.get(channelCode);
		if(cacheChannel != null) {
			return cacheChannel;
		}
		
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("channelCode", channelCode);

		try {
			List<Channel> result = (List<Channel>) this.queryForList("getChannleByCode", paramsMap);
			Channel channel = result.size() > 0 ? result.get(0) : null;
			
			if(channel != null) {
				List<ChannelParameter> params = (List<ChannelParameter>)this.queryForList("getAllChannleParameterOfChannel", paramsMap);
				channel.setParams(params);
			}
			return channel;
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * 
	 * @param channelCode
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getSchedulesOfChannel(String channelCode, Date startTime, Date endTime) {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("channelCode", channelCode);

		Date now = new Date();
		if (startTime == null) {
			startTime = DateUtils.addDay(now, -3);
		}

		if (endTime == null) {
			endTime = DateUtils.addDay(now, 1);
		}

		paramsMap.put("startTime", startTime);
		paramsMap.put("endTime", endTime);

		try {
			return (List<Schedule>) this.queryForList("getSchedulesOfChannel2", paramsMap);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}
	
	/**
	 * 
	 * @param channelCode
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getSchedulesOfChannel(String channelCode, Date startTime, Date endTime,PageBean pageBean) {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("channelCode", channelCode);

		Date now = new Date();
		if (startTime == null) {
			startTime = DateUtils.addDay(now, -3);
		}

		if (endTime == null) {
			endTime = DateUtils.addDay(now, 1);
		}

		paramsMap.put("startTime", startTime);
		paramsMap.put("endTime", endTime);

		try {
			return (List<Schedule>) this.queryForList("getSchedulesOfChannel", paramsMap,0,pageBean);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * 根据schedule编码查询频道.
	 * 
	 * @param scheduleCode
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Schedule getScheduleByCode(String scheduleCode) {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("code", scheduleCode);
		try {
			List<Schedule> result = (List<Schedule>) this.queryForList("getScheduleByCode", paramsMap);
			return result.size() > 0 ? result.get(0) : null;
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * @param paramsMap
	 * @param start
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getScheduleByTime(Map<String, Object> paramsMap, int start, int size) {
		try {
			return (List<Schedule>) this.queryForList("getScheduleByTime", paramsMap, start, size);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * @param paramsMap
	 * @param start
	 * @param pageBean
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getScheduleByTime(Map<String, Object> paramsMap, int start, PageBean pageBean) {
		try {
			return (List<Schedule>) this.queryForList("getScheduleByTime", paramsMap, start, pageBean);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * @param paramsMap
	 * @param start
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getPlayedSchedule(Map<String, Object> paramsMap, int start, int size) {
		paramsMap.put("curTime", new Date());

		try {
			return (List<Schedule>) this.queryForList("getAfterPlaySchedule", paramsMap, start, size);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * @param paramsMap
	 * @param start
	 * @param pageBean
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getPlayedSchedule(Map<String, Object> paramsMap, int start, PageBean pageBean) {
		paramsMap.put("curTime", new Date());

		try {
			return (List<Schedule>) this.queryForList("getAfterPlaySchedule", paramsMap, start, pageBean);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * @param paramsMap
	 * @param start
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getPlayingSchedule(Map<String, Object> paramsMap, int start, int size) {
		paramsMap.put("curTime", new Date());

		try {
			return (List<Schedule>) this.queryForList("getPlaySchedule", paramsMap, start, size);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * @param paramsMap
	 * @param start
	 * @param pageBean
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getPlayingSchedule(Map<String, Object> paramsMap, int start, PageBean pageBean) {
		paramsMap.put("curTime", new Date());

		try {
			return (List<Schedule>) this.queryForList("getPlaySchedule", paramsMap, start, pageBean);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * 
	 * @param categoryCode
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getFutureSchedule(Map<String, Object> paramsMap, int start, int size) {
		paramsMap.put("curTime", new Date());

		try {
			return (List<Schedule>) this.queryForList("getNextPlaySchedule", paramsMap, start, size);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	/**
	 * 
	 * @param categoryCode
	 * @param size
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getFutureSchedule(Map<String, Object> paramsMap, int start, PageBean pageBean) {
		paramsMap.put("curTime", new Date());

		try {
			return (List<Schedule>) this.queryForList("getNextPlaySchedule", paramsMap, start, pageBean);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	@SuppressWarnings("rawtypes")
	public void loadNowSchedules() {
		List<Schedule> schedules = this.queryNowSchedules();
		Map<String, Schedule> aScheduleMap = new ConcurrentHashMap<String, Schedule>();
		for (Iterator iterator = schedules.iterator(); iterator.hasNext();) {
			Schedule schedule = (Schedule) iterator.next();
			aScheduleMap.put(schedule.getChannelCode(), schedule);
		}
		Map<String, Schedule> old = nowSchedules;
		nowSchedules = aScheduleMap;
		old.clear();
	}

	@SuppressWarnings("rawtypes")
	public void loadNextSchedules() {
		List<Schedule> schedules = this.queryAfterSchedules();
		Map<String, Schedule> aScheduleMap = new ConcurrentHashMap<String, Schedule>();
		for (Iterator iterator = schedules.iterator(); iterator.hasNext();) {
			Schedule schedule = (Schedule) iterator.next();
			if (aScheduleMap.get(schedule.getChannelCode()) == null) {
				aScheduleMap.put(schedule.getChannelCode(), schedule);
			}
		}
		Map<String, Schedule> old = nextSchedules;
		nextSchedules = aScheduleMap;
		old.clear();
	}

	@SuppressWarnings("unchecked")
	public List<Schedule> queryNowSchedules() {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("now", new Date());
		return (List<Schedule>) this.queryForList("queryCurSchedule", paramsMap);
	}

	@SuppressWarnings("unchecked")
	public List<Schedule> queryAfterSchedules() {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		Date beginTime = new Date();
		Date endTime = org.apache.commons.lang.time.DateUtils.addHours(beginTime, 6);
		paramsMap.put("beginTime", beginTime);
		paramsMap.put("endTime", endTime);
		return (List<Schedule>) this.queryForList("queryAfterSchedule", paramsMap);
	}
	
	public Map<String, Schedule> getNowShcedules() {
		return ChannelService.nowSchedules;
	}

	public Schedule getNowShcedule(String channelCode) {
		return ChannelService.nowSchedules.get(channelCode);
	}

	public Schedule getNextShcedule(String channelCode) {
		return ChannelService.nextSchedules.get(channelCode);
	}
	
	/**
	 * 根据回看节目单类型获取回看节目单.
	 * @param type
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getSchedulesByType(String type,Date startTime,Date endTime,int size) {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("scheduleType", type);

		Date now = new Date();
		if (startTime == null) {
			startTime = DateUtils.addDay(now, -2);
		}

		if (endTime == null) {
			endTime = now;
		}

		paramsMap.put("beginTime", startTime);
		paramsMap.put("endTime", endTime);

		try {
			//return (List<Schedule>) this.queryForList("querySchedulesByType", paramsMap);
			return (List<Schedule>)this.queryForList("querySchedulesByType", paramsMap, 0, size);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}
	
	/**
	 * 根据回看节目单类型获取回看节目单.
	 * @param type
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Schedule> getSchedulesByType(String type,Date startTime,Date endTime) {
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("scheduleType", type);

		Date now = new Date();
		if (startTime == null) {
			startTime = DateUtils.addDay(now, -2);
		}

		if (endTime == null) {
			endTime = now;
		}

		paramsMap.put("beginTime", startTime);
		paramsMap.put("endTime", endTime);

		try {
			return (List<Schedule>) this.queryForList("querySchedulesByType", paramsMap);
		} finally {
			paramsMap.clear();
			paramsMap = null;
		}
	}

	@SuppressWarnings("unchecked")
	public List<CategoryItem> getCategoryItemSchedule(Map<String, Object> params, Integer start, Integer size) {
		return (List<CategoryItem>) this.queryForList("getCategoryItemSchedule", params, start, size);
	}

	@SuppressWarnings("unchecked")
	public List<CategoryItem> getCategoryItemSchedule(Map<String, Object> params, Integer start, PageBean pageBean) {
		return (List<CategoryItem>) this.queryForList("getCategoryItemSchedule", params, start, pageBean);
	}

	@SuppressWarnings("unchecked")
	public List<CategoryItem> getCategoryItemPastSchedule(Map<String, Object> params, Integer start, Integer size) {
		return (List<CategoryItem>) this.queryForList("getCategoryItemPastSchedule", params, start, size);
	}

	@SuppressWarnings("unchecked")
	public List<CategoryItem> getCategoryItemPastSchedule(Map<String, Object> params, Integer start,
			PageBean pageBean) {
		return (List<CategoryItem>) this.queryForList("getCategoryItemPastSchedule", params, start, pageBean);
	}

	@SuppressWarnings("unchecked")
	public List<CategoryItem> getCategoryItemPlaySchedule(Map<String, Object> params, Integer start, Integer size) {
		return (List<CategoryItem>) this.queryForList("getCategoryItemPlaySchedule", params, start, size);
	}

	@SuppressWarnings("unchecked")
	public List<CategoryItem> getCategoryItemPlaySchedule(Map<String, Object> params, Integer start,
			PageBean pageBean) {
		return (List<CategoryItem>) this.queryForList("getCategoryItemPlaySchedule", params, start, pageBean);
	}

	public List<Channel> getChannleList() {
		return channleList;
	}

}
